﻿using RockBus.DataContracts;
using RockBus.Routing.Interfaces;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;

namespace RockBus.Hosting.Web
{
    public class DynamicWebServicePathProvider : VirtualPathProvider
    {
        private ISubscriptionConfigurationManager SubscriptionConfigurationManager { get { return DependencyManager.Instance.Resolve<ISubscriptionConfigurationManager>(); } }

        public DynamicWebServicePathProvider()
        {
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            ReceivePortInfo rpi;
            if (this.IsPublisherEndpoint(virtualPath, out rpi))
            {
                string publisherId = rpi.PublisherInfo.Id;
                string receivePortId = rpi.Id;

                return new ServiceVirtualFile(virtualPath, publisherId, receivePortId);
            }
            else
            {
                return this.Previous.GetFile(virtualPath);
            }
        }

        public override bool FileExists(string virtualPath)
        {
            ReceivePortInfo rpi;
            if (this.IsPublisherEndpoint(virtualPath, out rpi))
            {
                return true;
            }
            else
            {
                return this.Previous.FileExists(virtualPath);
            }
        }

        public override bool DirectoryExists(string virtualPath)
        {
            ReceivePortInfo rpi;
            if (this.IsPublisherEndpoint(virtualPath, out rpi))
            {
                return true;
            }
            else
            {
                return this.Previous.DirectoryExists(virtualPath);
            }
        }

        public override VirtualDirectory GetDirectory(string virtualPath)
        {
            //if (this.Previous.DirectoryExists(virtualDir))
            //{
            //    return this.Previous.GetDirectory(virtualDir);
            //}
            //else
            //{
            //    return this.Previous.GetDirectory("/");
            //}

            ReceivePortInfo rpi;
            if (this.IsPublisherEndpoint(virtualPath, out rpi))
            {
                return new ServiceVirtualDirectory(virtualPath);
            }
            else
            {
                return this.Previous.GetDirectory(virtualPath);
            }
        }

        public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            ReceivePortInfo rpi;
            if (this.IsPublisherEndpoint(virtualPath, out rpi))
            {
                return null;
            }
            else
            {
                return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
            }
        }

        private bool IsPublisherEndpoint(string virtualPath, out ReceivePortInfo rpi)
        {
            var absolutePath = VirtualPathUtility.ToAbsolute(virtualPath);
            //var relativeAddress = virtualPath.Trim('~'); //VirtualPathUtility.ToAppRelative(virtualPath).Trim('~');

            var pc = this.SubscriptionConfigurationManager.PublisherConfiguration;

            // Retrieve the PublisherId and ReceivePortId from SubscriptionConfigurationManager using the virtual path
            return pc.TryFindReceivePortInfo(absolutePath, out rpi);
            //// TODO: change into looking whether this address is an address from a publisher endpoint
            //var checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
            //return checkPath.StartsWith("~/virtual", StringComparison.InvariantCultureIgnoreCase);
        }
    }

    public class ServiceVirtualFile : VirtualFile
    {
        private const string ServiceHostFileContentFormat = "<%@ ServiceHost Language=\"C#\" Debug=\"true\" Service=\"{0};{1}\" Factory=\"{2}\" %>";

        public ServiceVirtualFile(string virtualPath, string publisherId, string receivePortId)
            : base(virtualPath)
        {
            this.PublisherId = publisherId;
            this.ReceivePortId = receivePortId;
            this.ServiceHostFileContent = string.Format(
                ServiceHostFileContentFormat,
                this.PublisherId,
                this.ReceivePortId,
                typeof(DynamicWebServiceHostFactory).FullName
                );
        }

        private string PublisherId { get; set; }

        private string ReceivePortId { get; set; }

        private string ServiceHostFileContent { get; set; }

        public override Stream Open()
        {
            var serviceDef = new MemoryStream();
            var defWriter = new StreamWriter(serviceDef);

            // Write host definition
            defWriter.Write(this.ServiceHostFileContent);
            defWriter.Flush();

            serviceDef.Position = 0;
            return serviceDef;
        }
    }

    public class ServiceVirtualDirectory : VirtualDirectory
    {
        public ServiceVirtualDirectory(string virtualDir)
              : base(virtualDir)
        {
        }

        private ArrayList children = new ArrayList();
        public override IEnumerable Children
        {
            get { return children; }
        }

        private ArrayList directories = new ArrayList();
        public override IEnumerable Directories
        {
            get { return directories; }
        }

        private ArrayList files = new ArrayList();
        public override IEnumerable Files
        {
            get { return files; }
        }
    }
}
